/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ClassloaderTest;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

/**
 *
 * @author ph
 */
public class ClassloaderTest {

    private static String JAVAFILE = "/home/ph/ClassloaderTest/TestModule/src/TestModule.java";
    private static String SRCDIR = "/home/ph/ClassloaderTest/TestModule/src/";
    private static String CLASSDIR = "/home/ph/ClassloaderTest/TestModule/build/classes/";

    static class TestClassLoader extends ClassLoader {

        private long timeStamp;
        private File file;

        public void monitor(File f) {
            long tStamp = f.lastModified();

            if (this.timeStamp != tStamp) {
                this.timeStamp = tStamp;
                System.out.println("compiling");
                JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                OutputStream outStream = System.out;
                OutputStream errStream = System.err;
                int result = compiler.run(null, outStream, errStream, JAVAFILE, "-s", CLASSDIR);

                //Class cls;
                try {
                    Class cls = new TestClassLoader().findClass("TestModule");
                    Object obj = null;
                    try {
                        obj = cls.newInstance();
                    } catch (InstantiationException ex) {
                        Logger.getLogger(ClassloaderTest.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IllegalAccessException ex) {
                        Logger.getLogger(ClassloaderTest.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    System.out.println(obj);
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(ClassloaderTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        @Override
        public Class<?> findClass(String className) throws ClassNotFoundException {
            try {
                byte[] b = fetchClassFromFS(SRCDIR + className + ".class");
                return defineClass(className, b, 0, b.length);
            } catch (FileNotFoundException ex) {
                return super.findClass(className);
            } catch (IOException ex) {
                return super.findClass(className);
            }
        }

        private byte[] fetchClassFromFS(String path) throws FileNotFoundException, IOException {
            byte[] bytes;
            try (InputStream is = new FileInputStream(new File(path))) {
                long length = new File(path).length();
                bytes = new byte[(int) length];
                int offset = 0;
                int numRead = 0;
				boolean checkBytes = offset < bytes.length;
                while (checkBytes
                        && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
                    offset += numRead;
                }
                if (offset < bytes.length) {
                    throw new IOException("Could not completely read file " + path);
                }
            }
            return bytes;
        }

    }

    public static void main(String[] args) {
        File f = new File(JAVAFILE);
        TestClassLoader tcl = new TestClassLoader();
        while (true) {
            tcl.monitor(f);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
                Logger.getLogger(ClassloaderTest.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

}
